#include "Node.h"

Node::Node(ID3D10Device*	device ,std::string name)
	:m_pDevice(device)
	,m_nodeName(name)
	,m_pVB(NULL)
	,m_pIB(NULL)
	,m_iNumVertices(0)
	,m_iNumIndices(0)
	,m_iNumFaces(0)
	,m_bVisible(true)
	,m_vPostion(0,0,0)
	,m_vOrientation(0,0,-1)
	,m_vScale(1.0f,1.0f,1.0f)
	,m_vUp(0,1.0f,0.0)
	,m_vRight(-1,0,0)
	,m_pTextureMapRV(NULL)
	,m_parentNode(this)
{
	D3DXMatrixIdentity(&m_matWorld);
	UpdateWorldMatrix();
	D3DXMatrixIdentity(&m_matTexMtx);
}

Node::Node(std::string name)
	:m_pDevice(NULL)
	,m_nodeName(name)
	,m_pVB(NULL)
	,m_pIB(NULL)
	,m_iNumVertices(0)
	,m_iNumIndices(0)
	,m_iNumFaces(0)
	,m_bVisible(true)
	,m_vPostion(0,0,0)
	,m_vOrientation(0,0,-1)
	,m_vScale(1.0f,1.0f,1.0f)
	,m_vUp(0,1.0f,0.0)
	,m_vRight(-1,0,0)
	,m_pTextureMapRV(NULL)
	,m_parentNode(this)
{
	D3DXMatrixIdentity(&m_matWorld);
	UpdateWorldMatrix();
	D3DXMatrixIdentity(&m_matTexMtx);
}


Node::~Node(void)
{
}

void Node::SetWorldPosition( const D3DXVECTOR3& pos )
{
	m_vPostion = pos;
	UpdateWorldMatrix();
}

void Node::SetVertexBuffer( ID3D10Buffer* buffer ,DWORD numVertex )
{
	m_pVB = buffer;
	m_iNumVertices = numVertex;
}

void Node::SetIndexBuffer( ID3D10Buffer* buffer ,DWORD numIndex )
{
	m_pIB = buffer;
	m_iNumIndices = numIndex;
	m_iNumFaces = m_iNumIndices/3;
}

void Node::AttachTexture( ID3D10ShaderResourceView* texResView )
{
	m_pTextureMapRV = texResView;
}

ID3D10ShaderResourceView* Node::GetAttachTexture()
{
	return m_pTextureMapRV;
}

void Node::Draw()
{
	m_pDevice->DrawIndexed(m_iNumFaces*3,0,0);
}

void Node::Update()
{

}

void Node::SetOrientation( const D3DXVECTOR3& orien )
{
	D3DXVec3Normalize(&m_vOrientation,&orien);
	UpdateWorldMatrix();
}

void Node::AddChildNode( Node* child )
{
	if(child)
	{
		m_childNodeList.push_back(child);
		child->SetParentNode(this);
	}
}

void Node::SetParentNode( Node* parent )
{
	m_parentNode = parent;
}

void Node::UpdateWorldMatrix()
{
	D3DXMATRIX		translate;
	D3DXMATRIX		scale;

	D3DXMatrixTranslation(&translate,m_vPostion.x,m_vPostion.y,m_vPostion.z);
	D3DXMatrixScaling(&scale,m_vScale.x,m_vScale.y,m_vScale.z);

	//use the orientation to calculate the rotate
	D3DXVECTOR3		backWard;
	D3DXVec3Cross(&m_vRight,&m_vUp,&m_vOrientation);
	D3DXVec3Normalize(&m_vRight,&m_vRight);
	D3DXVec3Cross(&m_vUp,&m_vOrientation,&m_vRight);

	D3DXMATRIX		rotate(	m_vRight.x,m_vUp.x,m_vOrientation.x,0
							,m_vRight.y,m_vUp.y,m_vOrientation.y,0
							,m_vRight.z,m_vUp.z,m_vOrientation.z,0
							,0,0,0,1);

	m_matWorld = m_parentNode->GetWorldMatrix()*(scale*rotate*translate);
}

void Node::SetScaleFactor( const D3DXVECTOR3& scale )
{
	m_vScale = scale;
	UpdateWorldMatrix();
}

D3DXMATRIX Node::GetWorldMatrix()
{
	return m_matWorld;
}

D3DXMATRIX Node::GetTextureMatrix()
{
	return m_matTexMtx;
}

void Node::SetVisible( bool visible )
{
	m_bVisible = visible;
}

bool Node::IsVisible()
{
	return m_bVisible;
}

void Node::SetBuffer()
{
	UINT stride = sizeof(Vertex);
	UINT offset = 0;
	m_pDevice->IASetVertexBuffers(0, 1, &m_pVB, &stride, &offset);
	m_pDevice->IASetIndexBuffer(m_pIB, DXGI_FORMAT_R32_UINT, 0);

}

void Node::SetDevice( ID3D10Device* device )
{
	m_pDevice = device;
}

void Node::SetWorldMatrix( const D3DXMATRIX& mat )
{
	m_matWorld = mat;
}

void Node::pitch( float angle )
{
	D3DXMATRIX R;
	D3DXMatrixRotationAxis(&R, &m_vRight, angle);

	D3DXVec3TransformNormal(&m_vUp, &m_vUp, &R);
	D3DXVec3TransformNormal(&m_vOrientation, &m_vOrientation, &R);

	UpdateWorldMatrix();
}

void Node::yaw( float angle )
{
	D3DXMATRIX R;
	D3DXMatrixRotationAxis(&R, &m_vUp, angle);

	D3DXVec3TransformNormal(&m_vRight, &m_vRight, &R);
	D3DXVec3TransformNormal(&m_vOrientation, &m_vOrientation, &R);

	UpdateWorldMatrix();
}

void Node::roll( float angle )
{
	D3DXMATRIX R;
	D3DXMatrixRotationAxis(&R, &m_vOrientation, angle);

	D3DXVec3TransformNormal(&m_vUp, &m_vUp, &R);
	D3DXVec3TransformNormal(&m_vRight, &m_vRight, &R);

	UpdateWorldMatrix();
}

void Node::rotateY( float angle )
{
	D3DXMATRIX R;
	D3DXMatrixRotationY(&R, angle);

	D3DXVec3TransformNormal(&m_vRight, &m_vRight, &R);
	D3DXVec3TransformNormal(&m_vUp, &m_vUp, &R);
	D3DXVec3TransformNormal(&m_vOrientation, &m_vOrientation, &R);

	UpdateWorldMatrix();
}

void Node::SetUpVector( const D3DXVECTOR3& up )
{
	D3DXVec3Normalize(&m_vUp,&up);
	UpdateWorldMatrix();
}

D3DXVECTOR3 Node::GetPosition()
{
	return m_vPostion;
}
